package cn.itcast.account.service.impl;

import cn.itcast.account.entity.Account;
import cn.itcast.account.entity.AccountFreeze;
import cn.itcast.account.mapper.AccountFreezeMapper;
import cn.itcast.account.mapper.AccountMapper;
import cn.itcast.account.service.TCCAccountService;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class TCCAccountServiceImpl implements TCCAccountService {

    @Autowired
    private AccountFreezeMapper accountFreezeMapper;

    @Autowired
    private AccountMapper accountMapper;


    /**
     * 表示try阶段
     * name表示当前阶段的名称，名称可以随意起
     * commitMethod表示提交成功的方法名称
     * rollbackMethod表示回滚的方法名称
     * money是冻结金额
     * userId用户iD
     */
    @Override
    @Transactional
    public void tryTcc(String userId, Integer money) {

        //0.获取事务id
        String xid = RootContext.getXID();


        //设置避免业务悬挂
        AccountFreeze accountFreeze = accountFreezeMapper.selectById(xid);
        if(accountFreeze!=null){
            return;
        }



        //1.记录冻结金额和事务状态到account_freeze表中
        accountFreeze=new AccountFreeze();
        accountFreeze.setFreezeMoney(money);
        accountFreeze.setState(AccountFreeze.State.TRY);
        accountFreeze.setXid(xid);
        accountFreeze.setUserId(userId);
        accountFreezeMapper.insert(accountFreeze);

        //2.扣减account表的可用余额
        accountMapper.deduct(userId,money);
    }
    /**
     *  提交,表示没有异常才会执行该方法
     *  BusinessActionContext表示事务的上下文，可以从该上下文中获取相对应的属性
     */

    @Override
    public boolean confirmTcc(BusinessActionContext businessActionContext) {
        //1.根据xid删除account_freeze表的冻结记录
        String xid = businessActionContext.getXid();
        int i = accountFreezeMapper.deleteById(xid);
        return i==1;
    }
    /**
     *  回滚
     */

    @Override
    public boolean cancelTcc(BusinessActionContext businessActionContext) {

        //0.根据xid查询冻结记录
        String xid = businessActionContext.getXid();//从上下文中获取旧的xid
        AccountFreeze accountFreeze = accountFreezeMapper.selectById(xid);
        if(accountFreeze==null){
            //设置空回滚操作
             accountFreeze=new AccountFreeze();
            accountFreeze.setFreezeMoney(0);
            accountFreeze.setState(AccountFreeze.State.CANCEL);
            xid=RootContext.getXID();//重新生成的xid
            accountFreeze.setXid(xid);
            //获取用户id
            String userId = (String) businessActionContext.getActionContext("userId");
            accountFreeze.setUserId(userId);
            int insert = accountFreezeMapper.insert(accountFreeze);
            return insert==1;
        }


        //保证幂等性，不管执行多少次，结果都是唯一的
        if(accountFreeze.getState()==AccountFreeze.State.CANCEL){
            return  true;//终止
        }


        //1.修改account表，恢复可用余额
        accountMapper.refund(accountFreeze.getUserId(),accountFreeze.getFreezeMoney());

        //2.修改account_freeze表的冻结金额为0，并设置state=2
        accountFreeze.setFreezeMoney(0);
        accountFreeze.setState(AccountFreeze.State.CANCEL);
        int i = accountFreezeMapper.updateById(accountFreeze);

        return i==1;
    }
}
